# coding=utf-8
import os

from flask import Flask, g, request as g_request, Response

from apps.a_common.constants import USER_ID_JWT_COOKIES_KEY
from apps.a_common.error import exceptions, exception_handler, NotLogin, ER
from apps.a_common.jwt import Token, encode_token
from apps.a_common.log import MyLogger
from apps.a_common.permission import AnonymousUser
from apps.a_common.response import error_response
from apps.files.views import file_blueprint
from apps.foundation import db, redis, login_manager, cache, log, swagger
from apps.projects.views import project_blueprint, process_blueprint, checklist_blueprint
from apps.search.views import search_blueprint
from apps.users.views import user_blueprint, permission_blue_print, permission_group_blue_print, user_manage_blueprint
from config import NOT_LOGIN

# 命名规则如下，蓝图加上后缀，避免发生命名冲突，所有的资源都以复数形式呈现

V1_MODULES = [
    user_blueprint,
    file_blueprint,
    permission_blue_print,
    permission_group_blue_print,
    user_manage_blueprint,
    search_blueprint,
    project_blueprint,
    process_blueprint,
    checklist_blueprint
]

DEFAULT_APP_NAME = 'app'
DEFAULT_STATIC_DIR = 'app/static/'


def configure_blueprint(app):
    for module in V1_MODULES:
        app.register_blueprint(module, url_prefix='/v1/api')


def create_app(name=DEFAULT_APP_NAME, **settings_override):
    app = Flask(name)
    app.static_folder = os.path.abspath(DEFAULT_STATIC_DIR)
    app.config.from_object('config')
    app.config.update(settings_override)
    configure_foundations(app)
    configure_blueprint(app)
    return app


def load_user_from_request(request_):
    if hasattr(g, 'user'):
        return g.user

    logger = MyLogger(f'auth before request')
    user_token = request_.cookies.get(USER_ID_JWT_COOKIES_KEY, '').strip()
    logger.info(
        f'user token: {user_token}, remote_addr: {request_.remote_addr}, remote_user: {request_.remote_user}, NOT_LOGIN: {NOT_LOGIN}')
    g.token = user_token
    if NOT_LOGIN and user_token:
        # for test
        logger.info(f'easy test')
        admin_user_token = {
            'a5b5da03-e8e8-4bb7-a694-fb87b2a00a80': 1
        }
        user_id = admin_user_token.get(user_token)
        if user_id:
            logger.info(f'easy test')
            user_token = encode_token(user_id)
            g.token = user_token
            user = Token(user_token).get_user()
        else:
            user = Token(user_token).get_user()
    elif user_token:
        user = Token(user_token).get_user()
    else:
        user = AnonymousUser()

    logger.info(f'user is_authenticated: {user.is_authenticated}, user id: {user.id}')
    g.user = user
    return user


def configure_foundations(app):
    cache.init_app(app)
    db.app = app
    db.init_app(app)
    swagger.init_app(app)
    login_manager.init_app(app)

    @login_manager.unauthorized_handler
    def unauthorized_callback():
        return error_response(exceptions.NotLogin())

    @login_manager.request_loader
    def request_loader(request):
        return load_user_from_request(request)

    @app.before_request
    def before_request():
        log.info(f'[BEFORE REQUEST]{g_request.url}')
        load_user_from_request(g_request)

    @app.before_first_request
    def before_first_request():
        pass

    @app.after_request
    def after_request(response: Response):
        """ 避免跨域 """
        response.headers['Access-Control-Allow-Origin'] = '*'
        response.headers[
            'Access-Control-Allow-Methods'] = 'PUT,GET,POST,DELETE,VIEW'
        response.headers[
            'Access-Control-Allow-Headers'] = 'Content-Type, Mall-Token, User-Token'
        if response.is_json:
            log.info(f'[AFTER REQUEST]{response.json}')
        db.session.close()
        return response

    @app.errorhandler(Exception)
    def errorhandler(e):
        return exception_handler(e)

    @app.teardown_appcontext
    def releaseDB(response):
        db.session.close()
        return response


app = create_app()
